package com.boot.config;

import com.boot.pojo.CustomUserDetail;
import com.boot.result.Result;
import com.boot.service.UserService;
import com.boot.utils.JwtUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class JwtAuthorizationFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;
    private final UserService userService;
    private static final Set<String> WHITE_LIST = Set.of(
            "/user/login",
            "/user/register"
    );

    public JwtAuthorizationFilter(JwtUtil jwtUtil,
                                  UserService userService) {
        this.jwtUtil = jwtUtil;
        this.userService = userService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {


        //放行登录和注册路径
        if (WHITE_LIST.contains(request.getRequestURI())) {
            filterChain.doFilter(request, response);
            return;
        }

        // 1. 从请求头提取令牌
        String token = resolveToken(request);
        if (token == null || jwtUtil.isTokenExpired(token)) {
            sendErrorResponse(response, 30001, "token missed or expired", null);
            return;
        }
        try     {
            // 2. 从令牌中获取用户ID
            Long userId = jwtUtil.getUserIdByToken(token);

            // 3. 加载用户详细信息
            CustomUserDetail userDetail = userService.selectUserDetailById(userId);

            // 4. 创建认证对象
            Authentication authentication = new UsernamePasswordAuthenticationToken(
                    userDetail, null, userDetail.getAuthorities());

            // 5. 设置安全上下文
            SecurityContextHolder.getContext().setAuthentication(authentication);

        } catch (Exception ex) {
            // 令牌无效时清除上下文
            SecurityContextHolder.clearContext();
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token");
            return;
        }

        // 6. 继续过滤器链
        filterChain.doFilter(request, response);
    }

    private String resolveToken(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }

    //自定义返回错误
    private void sendErrorResponse(HttpServletResponse response,
                                   int code,
                                   String msg,
                                   Object data) throws IOException {
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        new ObjectMapper().writeValue(response.getOutputStream(), Result.build(data,code, msg));
    }
}
